include "heads.pyx"
from libc.stdint cimport uint64_t as u64, uint32_t as u32, uint8_t as u8, uint16_t as u16, int32_t as i32,\
    int16_t as i16, int8_t as i8, int64_t as i64, UINT64_MAX, UINT32_MAX, UINT16_MAX, INT64_MAX, INT64_MIN, UINT32_MAX, UINT8_MAX
from libc.string cimport memcpy, memcmp, memset, strlen, memmove

cdef u8 _encode_num(u64 num, u8* ptr):
    cdef u64 v=num>>7, vv=num, bytecount=1
    while(v>0):
        bytecount += 1
        vv=v
        v >>= 7
    cdef u64 i, prefix
    cdef u8* pn=<u8*>&num
    if bytecount<9:
        vv = num<<bytecount
        prefix = (1<<(bytecount-1))
        vv |= prefix
        memcpy(ptr, &vv, bytecount)
        return bytecount
    else:
        memcpy(ptr, &vv, 8)
        ptr[8]=0
        return 9
cpdef bytes encode_num_to_bytes(u64 num):
    cdef u8[9] buf
    cdef u8 bytecount=_encode_num(num, buf)
    return PyBytes_FromStringAndSize(<char*>buf, bytecount)

cpdef u8 get_num_bytecount(u8 c):
        if c&1:
            return 1
        elif c&2:
            return 2
        elif c&4:
            return 3
        elif c&8:
            return 4
        elif c&16:
            return 5
        elif c&32:
            return 6
        elif c&64:
            return 7
        elif c&128:
            return 8
        else: # c==0
            return 9


cdef u64 _decode_num(const u8* ptr, u64* bytecountp):
    cdef u64 bytecount = get_num_bytecount(ptr[0])
    cdef u64 v=0
    if bytecount<9:
        memcpy(&v, ptr, bytecount)
        v>>=bytecount
        bytecountp[0]=bytecount
        return v
    else:
        memcpy(&v, ptr+1, 8)
        bytecountp[0] = 9
        return v

cpdef decode_num_debug(const u8[:] view):
    cdef const u8* ptr=&view[0]
    cdef u64 bytecount, num = _decode_num(ptr, &bytecount)
    return num, bytecount

ctypedef fused uInt:
    u8
    u16
    u32
    u64


        




